// Homework Service - 作业管理服务

use axum::{
    extract::{Json, Path, Query, State},
    http::StatusCode,
    routing::{get, post, put},
    Router,
};
use common::{ApiResponse, UserRole};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use std::sync::Arc;
use std::time::Duration;
use auth::AuthUser;

// ========== 数据模型 ==========

#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
struct Homework {
    id: String,
    title: String,
    description: Option<String>,
    subject: String,
    class_id: String,
    teacher_id: String,
    deadline: chrono::DateTime<chrono::Utc>,
    status: String,
    questions: Option<serde_json::Value>,
    qrcode_url: Option<String>,
    created_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
struct HomeworkSubmission {
    id: String,
    homework_id: String,
    student_id: String,
    image_urls: serde_json::Value,  // JSON array
    status: String,
    submitted_at: chrono::DateTime<chrono::Utc>,
}

// ========== API 请求/响应 ==========

#[derive(Debug, Deserialize)]
struct CreateHomeworkRequest {
    title: String,
    description: Option<String>,
    subject: String,
    class_id: String,
    deadline: chrono::DateTime<chrono::Utc>,
    questions: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
struct CreateHomeworkResponse {
    id: String,
    qrcode_url: String,
}

#[derive(Debug, Deserialize)]
struct SubmitHomeworkRequest {
    homework_id: String,
    image_urls: Vec<String>,  // 前端已上传到 MinIO 的 URL 列表
}

#[derive(Debug, Deserialize)]
struct BatchSubmitRequest {
    homework_id: String,
    submissions: Vec<StudentSubmission>,  // 多个学生的提交
}

#[derive(Debug, Deserialize, Serialize)]
struct StudentSubmission {
    student_id: String,
    image_urls: Vec<String>,
}

#[derive(Debug, Serialize)]
struct SubmitHomeworkResponse {
    submission_id: String,
    message: String,
}

#[derive(Debug, Serialize)]
struct BatchSubmitResponse {
    total: usize,
    success: usize,
    failed: usize,
    results: Vec<SubmissionResult>,
}

#[derive(Debug, Serialize)]
struct SubmissionResult {
    student_id: String,
    success: bool,
    submission_id: Option<String>,
    error: Option<String>,
}

#[derive(Debug, Deserialize)]
struct ListQuery {
    subject: Option<String>,
    status: Option<String>,
    page: Option<i64>,
    page_size: Option<i64>,
}

#[derive(Debug, Serialize)]
struct HomeworkListItem {
    #[serde(flatten)]
    homework: Homework,
    total_students: i64,
    submitted_count: i64,
    graded_count: i64,
}

// ========== 应用状态 ==========

#[derive(Clone)]
struct AppState {
    db: PgPool,
}

// ========== 处理器 ==========

/// 健康检查
async fn health_check() -> (StatusCode, Json<ApiResponse<String>>) {
    (StatusCode::OK, Json(ApiResponse::ok("OK".to_string())))
}

/// 创建作业（仅教师）
async fn create_homework(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Json(req): Json<CreateHomeworkRequest>,
) -> (StatusCode, Json<ApiResponse<CreateHomeworkResponse>>) {
    // 检查权限：只有教师可以创建作业
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Teacher, UserRole::Admin]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("只有教师可以创建作业".to_string())),
        );
    }

    // 验证截止时间
    if req.deadline <= chrono::Utc::now() {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error("截止时间不能早于当前时间".to_string())),
        );
    }

    // 生成作业ID
    let homework_id = common::generate_id();
    
    // 生成二维码URL（简化版，实际应该调用二维码生成服务）
    let qrcode_url = format!("https://api.intelligrade.com/qr/homework/{}", homework_id);

    // 插入数据库
    let result = sqlx::query(
        r#"
        INSERT INTO homeworks (id, title, description, subject, class_id, teacher_id, deadline, questions, qrcode_url)
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
        "#
    )
    .bind(&homework_id)
    .bind(&req.title)
    .bind(&req.description)
    .bind(&req.subject)
    .bind(&req.class_id)
    .bind(&auth_user.user_id)
    .bind(&req.deadline)
    .bind(&req.questions)
    .bind(&qrcode_url)
    .execute(&state.db)
    .await;

    match result {
        Ok(_) => {
            tracing::info!("Homework created: {} by teacher {}", homework_id, auth_user.user_id);
            (
                StatusCode::CREATED,
                Json(ApiResponse::ok(CreateHomeworkResponse {
                    id: homework_id,
                    qrcode_url,
                })),
            )
        }
        Err(e) => {
            tracing::error!("Failed to create homework: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("创建作业失败".to_string())),
            )
        }
    }
}

/// 提交作业（仅学生）
async fn submit_homework(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Json(req): Json<SubmitHomeworkRequest>,
) -> (StatusCode, Json<ApiResponse<SubmitHomeworkResponse>>) {
    // 检查权限：只有学生可以提交作业
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Student]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("只有学生可以提交作业".to_string())),
        );
    }

    // 验证图片数量和格式
    if let Err(e) = validate_and_preprocess_images(&req.image_urls).await {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error(e)),
        );
    }

    // 检查作业是否存在且未关闭
    let homework = sqlx::query_as::<_, Homework>(
        "SELECT * FROM homeworks WHERE id = $1"
    )
    .bind(&req.homework_id)
    .fetch_optional(&state.db)
    .await;

    let homework = match homework {
        Ok(Some(hw)) => hw,
        Ok(None) => {
            return (
                StatusCode::NOT_FOUND,
                Json(ApiResponse::error("作业不存在".to_string())),
            );
        }
        Err(e) => {
            tracing::error!("Database error: {}", e);
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("查询作业失败".to_string())),
            );
        }
    };

    if homework.status == "closed" {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error("作业已关闭，无法提交".to_string())),
        );
    }

    // 生成提交ID
    let submission_id = common::generate_id();
    
    // 将 image_urls 转换为 JSON
    let image_urls_json = serde_json::json!(req.image_urls);

    // 插入提交记录
    let result = sqlx::query(
        r#"
        INSERT INTO homework_submissions (id, homework_id, student_id, image_urls)
        VALUES ($1, $2, $3, $4)
        ON CONFLICT (homework_id, student_id) 
        DO UPDATE SET image_urls = $4, updated_at = CURRENT_TIMESTAMP
        "#
    )
    .bind(&submission_id)
    .bind(&req.homework_id)
    .bind(&auth_user.user_id)
    .bind(&image_urls_json)
    .execute(&state.db)
    .await;

    match result {
        Ok(_) => {
            tracing::info!("Homework submitted: {} by student {}", submission_id, auth_user.user_id);
            (
                StatusCode::CREATED,
                Json(ApiResponse::ok(SubmitHomeworkResponse {
                    submission_id,
                    message: "作业提交成功".to_string(),
                })),
            )
        }
        Err(e) => {
            tracing::error!("Failed to submit homework: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("提交作业失败".to_string())),
            )
        }
    }
}

/// 批量提交作业（教师批量上传全班作业）
async fn batch_submit_homework(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Json(req): Json<BatchSubmitRequest>,
) -> (StatusCode, Json<ApiResponse<BatchSubmitResponse>>) {
    // 检查权限：只有教师可以批量提交
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Teacher, UserRole::Admin]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("只有教师可以批量提交作业".to_string())),
        );
    }

    // 验证作业是否存在
    let homework_exists: bool = sqlx::query_scalar(
        "SELECT EXISTS(SELECT 1 FROM homeworks WHERE id = $1)"
    )
    .bind(&req.homework_id)
    .fetch_one(&state.db)
    .await
    .unwrap_or(false);

    if !homework_exists {
        return (
            StatusCode::NOT_FOUND,
            Json(ApiResponse::error("作业不存在".to_string())),
        );
    }

    let total = req.submissions.len();
    let mut results = Vec::new();
    let mut success_count = 0;
    let mut failed_count = 0;

    // 并发处理所有提交（用 Tokio）
    for submission in req.submissions {
        // 验证图片数量和预处理
        let validation_result = validate_and_preprocess_images(&submission.image_urls).await;
        
        if let Err(e) = validation_result {
            results.push(SubmissionResult {
                student_id: submission.student_id.clone(),
                success: false,
                submission_id: None,
                error: Some(e),
            });
            failed_count += 1;
            continue;
        }

        // 生成提交ID
        let submission_id = common::generate_id();
        let image_urls_json = serde_json::json!(submission.image_urls);

        // 插入数据库
        let result = sqlx::query(
            r#"
            INSERT INTO homework_submissions (id, homework_id, student_id, image_urls)
            VALUES ($1, $2, $3, $4)
            ON CONFLICT (homework_id, student_id) 
            DO UPDATE SET image_urls = $4, updated_at = CURRENT_TIMESTAMP
            "#
        )
        .bind(&submission_id)
        .bind(&req.homework_id)
        .bind(&submission.student_id)
        .bind(&image_urls_json)
        .execute(&state.db)
        .await;

        match result {
            Ok(_) => {
                results.push(SubmissionResult {
                    student_id: submission.student_id,
                    success: true,
                    submission_id: Some(submission_id),
                    error: None,
                });
                success_count += 1;
            }
            Err(e) => {
                tracing::error!("Failed to insert submission: {}", e);
                results.push(SubmissionResult {
                    student_id: submission.student_id,
                    success: false,
                    submission_id: None,
                    error: Some("数据库插入失败".to_string()),
                });
                failed_count += 1;
            }
        }
    }

    tracing::info!(
        "Batch submit completed: total={}, success={}, failed={}",
        total, success_count, failed_count
    );

    (
        StatusCode::OK,
        Json(ApiResponse::ok(BatchSubmitResponse {
            total,
            success: success_count,
            failed: failed_count,
            results,
        })),
    )
}

// ========== 图片预处理 ==========

/// 验证和预处理图片（质量检查、格式验证）
async fn validate_and_preprocess_images(image_urls: &[String]) -> Result<(), String> {
    // 1. 验证图片数量
    if image_urls.is_empty() {
        return Err("图片数量不能为空".to_string());
    }
    if image_urls.len() > 10 {
        return Err("图片数量不能超过10张".to_string());
    }

    // 2. 验证 URL 格式（简化版）
    for url in image_urls {
        if !url.starts_with("http://") && !url.starts_with("https://") {
            return Err(format!("无效的图片 URL: {}", url));
        }

        // 验证文件扩展名
        let valid_extensions = [".jpg", ".jpeg", ".png", ".webp", ".heic"];
        let has_valid_ext = valid_extensions.iter().any(|ext| {
            url.to_lowercase().contains(ext)
        });

        if !has_valid_ext {
            return Err("不支持的图片格式，仅支持 JPG, PNG, WEBP, HEIC".to_string());
        }
    }

    // 3. TODO: 实际的图片质量检查（需要下载图片）
    // - 检查图片清晰度
    // - 检查图片大小（< 10MB）
    // - 格式转换（HEIC -> JPEG）
    // - 自动压缩

    Ok(())
}

/// 获取作业列表
async fn list_homeworks(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Query(query): Query<ListQuery>,
) -> (StatusCode, Json<ApiResponse<Vec<HomeworkListItem>>>) {
    let page = query.page.unwrap_or(1).max(1);
    let page_size = query.page_size.unwrap_or(20).min(100);
    let offset = (page - 1) * page_size;

    // 根据角色构建查询
    let homeworks = if auth_user.role == UserRole::Teacher || auth_user.role == UserRole::Admin {
        // 教师：查询自己创建的作业
        let mut query_str = "SELECT * FROM homeworks WHERE teacher_id = $1".to_string();
        let mut params_count = 2;

        if let Some(_subject) = &query.subject {
            query_str.push_str(&format!(" AND subject = ${}", params_count));
            params_count += 1;
        }
        if let Some(_status) = &query.status {
            query_str.push_str(&format!(" AND status = ${}", params_count));
            params_count += 1;
        }

        query_str.push_str(&format!(" ORDER BY created_at DESC LIMIT ${} OFFSET ${}", params_count, params_count + 1));

        let mut query_builder = sqlx::query_as::<_, Homework>(&query_str)
            .bind(&auth_user.user_id);

        if let Some(subject) = &query.subject {
            query_builder = query_builder.bind(subject);
        }
        if let Some(status) = &query.status {
            query_builder = query_builder.bind(status);
        }

        query_builder
            .bind(page_size)
            .bind(offset)
            .fetch_all(&state.db)
            .await
    } else {
        // 学生：查询所有作业（实际应该根据班级过滤）
        sqlx::query_as::<_, Homework>(
            "SELECT * FROM homeworks ORDER BY deadline ASC LIMIT $1 OFFSET $2"
        )
        .bind(page_size)
        .bind(offset)
        .fetch_all(&state.db)
        .await
    };

    match homeworks {
        Ok(homeworks) => {
            let mut list = Vec::new();
            for hw in homeworks {
                let stats: (i64, i64) = sqlx::query_as(
                    "SELECT 
                        COUNT(DISTINCT hs.student_id) as submitted,
                        COUNT(DISTINCT gr.id) as graded
                     FROM homework_submissions hs
                     LEFT JOIN grading_results gr ON hs.id = gr.submission_id
                     WHERE hs.homework_id = $1"
                )
                .bind(&hw.id)
                .fetch_one(&state.db)
                .await
                .unwrap_or((0, 0));

                list.push(HomeworkListItem {
                    homework: hw,
                    total_students: 0,
                    submitted_count: stats.0,
                    graded_count: stats.1,
                });
            }

            (StatusCode::OK, Json(ApiResponse::ok(list)))
        }
        Err(e) => {
            tracing::error!("Failed to fetch homeworks: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("查询作业列表失败".to_string())),
            )
        }
    }
}

/// 获取作业详情
async fn get_homework(
    _auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Path(homework_id): Path<String>,
) -> (StatusCode, Json<ApiResponse<Homework>>) {
    let homework = sqlx::query_as::<_, Homework>(
        "SELECT * FROM homeworks WHERE id = $1"
    )
    .bind(&homework_id)
    .fetch_optional(&state.db)
    .await;

    match homework {
        Ok(Some(hw)) => (StatusCode::OK, Json(ApiResponse::ok(hw))),
        Ok(None) => (
            StatusCode::NOT_FOUND,
            Json(ApiResponse::error("作业不存在".to_string())),
        ),
        Err(e) => {
            tracing::error!("Database error: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("查询失败".to_string())),
            )
        }
    }
}

/// 更新作业状态
async fn update_homework_status(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Path(homework_id): Path<String>,
    Json(req): Json<UpdateStatusRequest>,
) -> (StatusCode, Json<ApiResponse<String>>) {
    // 检查权限：仅教师可以更新状态
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Teacher, UserRole::Admin]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("仅教师可以更新作业状态".to_string())),
        );
    }

    // 验证状态值
    if !["active", "closed", "grading", "completed"].contains(&req.status.as_str()) {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error("无效的状态值".to_string())),
        );
    }

    // 更新状态
    let result = sqlx::query(
        "UPDATE homeworks SET status = $1, updated_at = NOW() WHERE id = $2 AND teacher_id = $3"
    )
    .bind(&req.status)
    .bind(&homework_id)
    .bind(&auth_user.user_id)
    .execute(&state.db)
    .await;

    match result {
        Ok(r) if r.rows_affected() > 0 => {
            tracing::info!("Homework {} status updated to {}", homework_id, req.status);
            (StatusCode::OK, Json(ApiResponse::ok("状态更新成功".to_string())))
        }
        Ok(_) => (
            StatusCode::NOT_FOUND,
            Json(ApiResponse::error("作业不存在或无权限".to_string())),
        ),
        Err(e) => {
            tracing::error!("Failed to update status: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("更新失败".to_string())),
            )
        }
    }
}

// ========== 定时任务 ==========

/// 自动关闭过期作业（后台任务）
async fn auto_close_expired_homeworks(db: PgPool) {
    let mut interval = tokio::time::interval(Duration::from_secs(60)); // 每分钟检查一次
    
    loop {
        interval.tick().await;
        
        // 查找并关闭过期的作业
        let result = sqlx::query(
            r#"
            UPDATE homeworks 
            SET status = 'closed', updated_at = NOW()
            WHERE status = 'active' AND deadline < NOW()
            RETURNING id
            "#
        )
        .fetch_all(&db)
        .await;

        match result {
            Ok(rows) => {
                if !rows.is_empty() {
                    tracing::info!("Auto-closed {} expired homeworks", rows.len());
                    
                    // TODO: 发送通知给未提交的学生
                }
            }
            Err(e) => {
                tracing::error!("Failed to auto-close expired homeworks: {}", e);
            }
        }
    }
}

// ========== 辅助结构 ==========

#[derive(Debug, Deserialize)]
struct UpdateStatusRequest {
    status: String,
}

// ========== 主函数 ==========

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    use common::service::*;
    
    init_tracing();
    dotenvy::dotenv().ok();

    let db = init_db("DATABASE_URL", "postgresql://intelligrade:password@localhost:5432/intelligrade").await?;

    // 启动定时任务
    tokio::spawn(auto_close_expired_homeworks(db.clone()));

    let app = Router::new()
        .route("/health", get(health_check))
        .route("/api/v1/homeworks", post(create_homework).get(list_homeworks))
        .route("/api/v1/homeworks/:id", get(get_homework))
        .route("/api/v1/homeworks/:id/status", put(update_homework_status))
        .route("/api/v1/homeworks/submit", post(submit_homework))
        .route("/api/v1/homeworks/batch-submit", post(batch_submit_homework))
        .with_state(Arc::new(AppState { db }));

    start_service("Homework service", &env_or("HOMEWORK_SERVICE_PORT", "8082"), app).await
}
